package diy

import (
	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/layout"
	"fyne.io/fyne/v2/theme"
	"fyne.io/fyne/v2/widget"
)

type DiyForm struct {
	*widget.PopUp
	Buttons *fyne.Container
	OnShow  func()
}

// NewForm 自定义Form
func NewForm(
	baseCanvasObj fyne.CanvasObject,
	callback func(),
	chkFunc func() string,
	title string,
	isModal bool,
	formItems ...*FormItem,
) *DiyForm {
	// 标题
	_titleLabel := widget.NewLabelWithStyle(title, fyne.TextAlignLeading, fyne.TextStyle{Bold: true})

	// 填写框
	_formItems := make([]fyne.CanvasObject, len(formItems)*2)
	for idx, formItem := range formItems {
		_formItems[idx*2] = widget.NewLabel(formItem.Text)
		_formItems[idx*2+1] = formItem.CanvasObj
	}
	_formContent := container.New(
		layout.NewFormLayout(),
		_formItems...,
	)

	// 按钮
	var _pass bool
	_popUpCloseChan := make(chan bool)
	_buttons := container.NewHBox(
		layout.NewSpacer(),
		&widget.Button{
			Text: "取消",
			Icon: theme.CancelIcon(),
			OnTapped: func() {
				_popUpCloseChan <- true

			},
		},
		&widget.Button{
			Text:       "确定",
			Icon:       theme.ConfirmIcon(),
			Importance: widget.HighImportance,
			OnTapped: func() {
				if chkFunc != nil {
					_chkRes := chkFunc()
					// 校验不通过
					if _chkRes != "success" {
						ShowInformation(_chkRes, baseCanvasObj)
						return
					}
				}
				_pass = true
				_popUpCloseChan <- true
			},
		},
		layout.NewSpacer(),
	)

	var _showInfoPopUp *widget.PopUp
	if isModal {
		_showInfoPopUp = widget.NewModalPopUp(
			container.New(
				&formLayout{},
				_titleLabel,
				_formContent,
				_buttons,
			),
			fyne.CurrentApp().Driver().CanvasForObject(baseCanvasObj),
		)
	} else {
		_showInfoPopUp = widget.NewPopUp(
			container.New(
				&formLayout{},
				_titleLabel,
				_formContent,
				_buttons,
			),
			fyne.CurrentApp().Driver().CanvasForObject(baseCanvasObj),
		)
	}

	// form对话框
	_diyForm := &DiyForm{
		PopUp:   _showInfoPopUp,
		Buttons: _buttons,
	}
	go func() {
		select {
		case <-_popUpCloseChan:
		}
		_showInfoPopUp.Hide()
		if _pass && callback != nil {
			callback()
		}
	}()

	return _diyForm
}

// ShowForm 显示自定义form
func ShowForm(baseCanvasObj fyne.CanvasObject, callback func(), chkFunc func() string, title string, isModal bool, formItems ...*FormItem) {
	_diyForm := NewForm(baseCanvasObj, callback, chkFunc, title, true, formItems...)
	_diyForm.Show()
}

func (d *DiyForm) DoSubmit(text string) {
	d.Buttons.Objects[2].(*widget.Button).OnTapped()
}

func (d *DiyForm) Show() {
	if d.OnShow != nil {
		d.OnShow()
	}
	d.PopUp.Show()

}

// FormItem 表单填写项
type FormItem struct {
	Text      string
	CanvasObj fyne.CanvasObject
}

// NewFormItem 创建一个表单填写项
func NewFormItem(text string, canvasObj fyne.CanvasObject) *FormItem {
	return &FormItem{
		Text:      text,
		CanvasObj: canvasObj,
	}
}

/*
	formLayout 容器
*/

type formLayout struct {
}

const (
	padWidth  = 32
	padHeight = 16
)

func (l *formLayout) Layout(obj []fyne.CanvasObject, size fyne.Size) {
	_title := obj[0]
	_content := obj[1]
	_contentMin := _content.MinSize()
	// 根据formItems的数量计算form.height的实际大小
	_contentSizeHeight := _contentMin.Height * float32(len(_content.(*fyne.Container).Objects)/2)
	button := obj[2]
	btnMin := button.MinSize()

	// content
	contentStart := _title.Position().Y + _title.MinSize().Height + padHeight
	contentEnd := contentStart + _contentSizeHeight
	_content.Move(fyne.NewPos(padWidth/2, _title.MinSize().Height+padHeight))
	_contentX := size.Width - padWidth
	_contentY := contentEnd - contentStart
	_content.Resize(fyne.NewSize(_contentX, _contentY))

	// buttons
	button.Resize(btnMin)
	_buttonMoveX := size.Width/2 - (btnMin.Width / 2)
	_buttonMoveY := size.Height - btnMin.Height - padHeight
	button.Move(fyne.NewPos(_buttonMoveX, _buttonMoveY))

}

func (l *formLayout) MinSize(obj []fyne.CanvasObject) fyne.Size {
	titleMin := obj[0].MinSize()
	contentMin := obj[1].MinSize()
	btnMin := obj[2].MinSize()

	width := fyne.Max(fyne.Max(contentMin.Width, btnMin.Width), titleMin.Width) + padWidth
	height := contentMin.Height + btnMin.Height + titleMin.Height + theme.Padding() + padHeight*2

	return fyne.NewSize(width, height)
}
